#include "precompiled.h"
#include "affliction.h"
using namespace std;
using namespace weo::engine::item;
using namespace weo::engine::character::warlock;

Affliction::Affliction()
{
    m_AttributesVector.push_back("Mana");
    m_AttributesVector.push_back("Intellect");
    m_AttributesVector.push_back("Spirit");
    m_AttributesVector.push_back("SpellDamage");
    m_AttributesVector.push_back("ShadowSpellDamage");
    m_AttributesVector.push_back("FireSpellDamage");
    m_AttributesVector.push_back("CritSpellRating");
    m_AttributesVector.push_back("HasteSpellRating");
    m_AttributesVector.push_back("HitSpellRating");
    m_AttributesVector.push_back("MP5");
    m_AttributesVector.push_back("HP5");
    m_AttributesVector.push_back("Health");
    Casterdps::Init();
    m_Classnr = weo::engine::character::Character::isAllowed("Warlock");
    m_Basevalues.push_back(Attribute("Agility",55));
    m_Basevalues.push_back(Attribute("Intellect",130));
    m_Basevalues.push_back(Attribute("Strength",54));
    m_Basevalues.push_back(Attribute("Stamina",78));
    m_Basevalues.push_back(Attribute("Spirit",142));
    m_Basevalues.push_back(Attribute("Health",3460)); // health
    m_Basevalues.push_back(Attribute("Mana",2335)); // mana
    m_Basevalues.push_back(Attribute("CritSpellRating",1.5f*CritSpellRating));
    // talents
    m_Basevalues.push_back(Attribute("SpellDmg",100));
    m_Equip.Mode(0);
    BOOST_FOREACH(Attribute attr, m_Basevalues)
    {
        handleAttribute(attr);
    }
    // base settings finished
    Buff *puredeath = new Buff("Flask of Pure Death");
    puredeath->addAttribute(Attribute("ShadowSpellDamage", 80));
    puredeath->addAttribute(Attribute("FireSpellDamage", 80));
    puredeath->addAttribute(Attribute("FrostSpellDamage", 80));
    m_Buffs[puredeath->Name()] = *puredeath;
    m_Buffs["Bloodpact"].Active(true);
}
// mana, int, spirit, shadowspelldmg, firespelldmg, spellcrit, spellhit, spellhaste, mp5,hp5, health
float Affliction::evaluateTF()
{
    float runtime = 600;
    float mana = m_Equip[35];
    float intellect = m_Equip[2];
    float spirit = m_Equip[5];
    float shadowdmg = m_Equip[23] + m_Equip[29];
    float firedmg = m_Equip[23] + m_Equip[24];
    float crit = m_Equip[12] / CritSpellRating;
    float hit = m_Equip[11] / HitSpellRating;
    float haste = m_Equip[13] / HasteSpellRating;
    float health = m_Equip[34];
    float mp5 = m_Equip[21];
    float hp5 = m_Equip[22];
    float affhit = min<float>(99, 83 + hit + 10.0f);
    hit = min<float>(99, 83 + hit);
    float time = runtime;
    float corruptionmana = 340;
    float corruptiondmg = 900 + 1.05f * 1.36f * 0.92f * shadowdmg;
    float destcrit = (crit+5)/100;
    float nonimpsb = (float) pow(destcrit, 4.0f);
    float shadowdmgmod = 1 + (nonimpsb * destcrit * 0.5f + (1 - destcrit) * nonimpsb * 0 + destcrit * (1 - nonimpsb) * 0.8f + (1 - nonimpsb) * (1 - destcrit) * 0.2f);
    float sbcasttime = 2.5f/(1+haste/100);
    if(m_Equip.hasSpecial(1254409))
    {
        shadowdmg += min<float>(1.0f,(30.0f/sbcasttime)*(crit/100)*0.2f) * (190.0f/4.0f);
    }
    if(m_Equip.hasSpecial(445202)) // chaos metagem
    {
        crit *= 1.03f;
        destcrit *= 1.03f;
    }        
    float shadowboltmana = 420;
    float shadowboltdmg = (1 + 0.5f * destcrit) * (572 + (6.0f / 7.0f) * shadowdmg);
    if(m_Equip.hasSpecial(992999)) // t6 4p
    {
        shadowboltdmg *= 1.06f;
    }
    float lifetap = 580 + 0.8f * shadowdmg;
    float immolatedmg = (1 + 0.5f * destcrit) * (327 + 0.20f * firedmg) + (615 + 0.65f * firedmg);
    float immolatemana = 445;
    float uadmg = 1050 + 1.2f * shadowdmg;
    float uamana = 400;
    float coamana = 265;
    float coadmg = 1356 + 1.2f * shadowdmg;
    // coa-ua-corr-immo-sb-sb-sb-sb-dp-lt
    float rotdmg = (affhit / 100) * 1.1f * ((24 / 18.0f) * corruptiondmg + (24.0f / 18.0f) * uadmg + 1.1f * coadmg) + 1.1f * (hit / 100) * ((shadowdmgmod * 4 * shadowboltdmg) + (24.0f / 15.0f) * immolatedmg);
    float rottime = 24;
    float rotmana = max<float>(shadowboltmana * 4 + corruptionmana + uamana + coamana + immolatemana - lifetap - (mp5 / 5.0f) * 24.0f - 700, 1.0f);
    float rotcount = min<float>(mana / rotmana, time / rottime);
    float finaldps = (rotdmg * rotcount) / runtime;
    return m_CondFactor * finaldps;
}
void Affliction::filterEquip(std::vector<std::vector<const weo::engine::item::Item*>>& items)
{
    for(unsigned int i = 0;i<10;i++)
    {
        int subtype = 3;
        if(i == 1 || i == 3)
        {
            vector<const Item*> temp = m_Database->getPtrbyType(1,i+1);
            items.push_back(temp);
        }
        else
        {
            vector<const Item*> temp = m_Database->getPtrbyType(1,i+1,1); // cloth	
            items.push_back(temp);
        }
    }
    items.push_back(m_Database->getPtrbyType(2,0));
    items.push_back(m_Database->getPtrbyType(2,0));
    items.push_back(m_Database->getPtrbyType(3,0));
    items.push_back(m_Database->getPtrbyType(3,0));
    // main hand weapons
    vector<const Item*> mainhand;
    for(int j = 1;j<3;j++)
    {
        vector<const Item*> weapon = m_Database->getPtrbyType(4,j,1);
        vector<const Item*>::iterator it;
        for(it=weapon.begin();it!=weapon.end();it++)
        {
            mainhand.push_back(*it);
        }
    }
    for(int j = 1;j<3;j++)
    {
        vector<const Item*> weapon = m_Database->getPtrbyType(4,j,5);
        vector<const Item*>::iterator it;
        for(it=weapon.begin();it!=weapon.end();it++)
        {
            mainhand.push_back(*it);
        }
    }
    // staff
    vector<const Item*> staff = m_Database->getPtrbyType(4,4,6);
    vector<const Item*>::iterator it;
    for(it=staff.begin();it!=staff.end();it++)
    {
        mainhand.push_back(*it);
    }
    // off hand weapons
    vector<const Item*> offhand = m_Database->getPtrbyType(1,12);
    items.push_back(mainhand);
    items.push_back(offhand);
    items.push_back(m_Database->getPtrbyType(4,5,13)); // wands
    items.push_back(m_Database->getPtrbyType(5,0));
    Casterdps::filterEquip(items);
}
void Affliction::handleAttribute(const Attribute& attr)
{
    switch(attr.Type())
    {		
    default:
        Casterdps::handleAttribute(attr);
        break;
    }
}
